package cn.iocoder.yudao.module.vote.service.voteuserresult;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.vote.constants.RedisConst;
import cn.iocoder.yudao.module.vote.constants.VoteConfigTypeEnum;
import cn.iocoder.yudao.module.vote.constants.VotePersonTypeEnum;
import cn.iocoder.yudao.module.vote.constants.VoteReviewerTypeEnum;
import cn.iocoder.yudao.module.vote.controller.admin.fielddynamicsconfig.vo.FieldInfoVO;
import cn.iocoder.yudao.module.vote.controller.admin.voteinfo.vo.OnlineVoteParamsVO;
import cn.iocoder.yudao.module.vote.controller.admin.voterecorddetail.vo.VoteRecordCountVO;
import cn.iocoder.yudao.module.vote.controller.admin.voteuserresult.vo.*;
import cn.iocoder.yudao.module.vote.convert.voteuserresult.VoteUserResultConvert;
import cn.iocoder.yudao.module.vote.dal.dataobject.dept.VoteDeptDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.fielddynamicsconfig.FieldDynamicsConfigDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.voteconfig.VoteConfigDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.voteinfo.VoteInfoDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.voteuserinfodetail.VoteUserInfoDetailDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.voteuserresult.VoteUserResultDO;
import cn.iocoder.yudao.module.vote.dal.dataobject.voteuserresultdetail.VoteUserResultDetailDO;
import cn.iocoder.yudao.module.vote.dal.mysql.dept.VoteDeptMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voteconfig.VoteConfigMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voteinfo.VoteInfoMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voterecorddetail.VoteRecordDetailMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voteuserinfodetail.VoteUserInfoDetailMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voteuserresult.VoteUserResultMapper;
import cn.iocoder.yudao.module.vote.dal.mysql.voteuserresultdetail.VoteUserResultDetailMapper;
import cn.iocoder.yudao.module.vote.service.fielddynamicsconfig.FieldDynamicsConfigService;
import cn.iocoder.yudao.module.vote.service.voterecord.VoteRecordService;
import cn.iocoder.yudao.module.vote.service.voteuserresult.strategy.ScopeStrategyFactory;
import cn.iocoder.yudao.module.vote.utils.RedisService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Predicate;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.vote.constants.RedisConst.VOTEUSERRESULTH5LIST_KEY;
import static cn.iocoder.yudao.module.vote.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.vote.utils.VoteUserResultGroupVOUtil.buildNestedStructure;

/**
 * 投票结果 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class VoteUserResultServiceImpl extends ServiceImpl<VoteUserResultMapper,VoteUserResultDO> implements VoteUserResultService {

    @Resource
    private VoteUserResultMapper userResultMapper;
    @Resource
    private VoteInfoMapper voteInfoMapper;
    @Resource
    private VoteUserInfoDetailMapper voteUserInfoDetailMapper;
    @Resource
    private VoteRecordService voteRecordService;
    @Resource
    private VoteConfigMapper voteConfigMapper;
    @Resource
    private VoteRecordDetailMapper recordDetailMapper;
    @Resource
    private VoteUserResultDetailMapper resultDetailMapper;
    @Resource
    private VoteDeptMapper voteDeptMapper;
    @Resource
    private FieldDynamicsConfigService dynamicsConfigService;
    @Resource
    private RedisService redisService;

    @Resource
    private ScopeStrategyFactory scopeStrategyFactory;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createUserResult(VoteUserResultCreateReqVO createReqVO) {

        VoteInfoDO vote = existVote(createReqVO.getVoteId());

        VoteUserResultDO existUser = userResultMapper.selectByMobile(createReqVO.getVoteId(),createReqVO.getMobile());
        if(existUser!=null) {
            throw exception(USER_RESULT_MOBILE_EXISTS);
        }


        VoteUserResultDO resultDO =  VoteUserResultConvert.INSTANCE.convert(createReqVO);
        resultDO.setVoteName(vote.getVoteName());
        resultDO.setVoteId(vote.getId());
        resultDO.setVoteType(vote.getVoteType());

        VoteUserInfoDetailDO userInfoDetail = voteUserInfoDetailMapper.selectByMobile(createReqVO.getMobile());
        if(userInfoDetail!=null){
            resultDO.setContent(userInfoDetail.getContent());
            resultDO.setFileUrl(userInfoDetail.getFileUrl());
        }
        // 插入
        userResultMapper.insert(resultDO);

        VoteUserResultDetailDO detailDO = new VoteUserResultDetailDO();
        detailDO.setAppraiseUrl(createReqVO.getAppraiseUrl());
        detailDO.setAssessUrl(createReqVO.getAssessUrl());
        detailDO.setEvidenceUrl(createReqVO.getEvidenceUrl());
        detailDO.setInfoUrl(createReqVO.getInfoUrl());
        detailDO.setRecommendUrl(createReqVO.getRecommendUrl());
        detailDO.setResultId(resultDO.getId().longValue());
        resultDetailMapper.insert(detailDO);
        // 返回
        return resultDO.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserResult(VoteUserResultUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateUserResultExists(updateReqVO.getId());

        VoteUserResultDO existUser = userResultMapper.selectByMobile(updateReqVO.getVoteId(),updateReqVO.getMobile());
        if(existUser!=null && !existUser.getId().equals(updateReqVO.getId())) {
            throw exception(USER_RESULT_MOBILE_EXISTS);
        }
        // 更新
        VoteUserResultDO updateObj = VoteUserResultConvert.INSTANCE.convert(updateReqVO);
        userResultMapper.updateById(updateObj);

        VoteUserResultDetailDO detailDO = resultDetailMapper.selectByResultId(updateReqVO.getId().longValue());
        if(detailDO==null){
            detailDO = new VoteUserResultDetailDO();
        }
        detailDO.setAppraiseUrl(updateReqVO.getAppraiseUrl());
        detailDO.setAssessUrl(updateReqVO.getAssessUrl());
        detailDO.setEvidenceUrl(updateReqVO.getEvidenceUrl());
        detailDO.setInfoUrl(updateReqVO.getInfoUrl());
        detailDO.setRecommendUrl(updateReqVO.getRecommendUrl());
        detailDO.setResultId(updateReqVO.getId().longValue());
        if(detailDO.getId()==null) {
            resultDetailMapper.insert(detailDO);
        }else{
            resultDetailMapper.updateById(detailDO);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOnlineResult(VoteOnlineUpdateReqVO onlineReq) {
        if(voteRecordService.isVote(onlineReq.getVoteId(),onlineReq.getIp())){
            throw exception(USER_RESULT_SUBMIT_EXISTS);
        }
        VoteInfoDO voteInfoDO =existVote(onlineReq.getVoteId());

        if (new Date().after(voteInfoDO.getEndTime())) {
            throw exception(INFO_TIME_END);
        }
        if(!voteInfoDO.getIsPush()){
            exception(INFO_TIME_NOTSTART);
        }

        onlineReq.setVoteName(voteInfoDO.getVoteName());
        onlineReq.setVoteType(voteInfoDO.getVoteType());
        onlineReq.setVoteMode(voteInfoDO.getVoteMode());
        onlineReq.setTenantId(voteInfoDO.getTenantId());
        voteRecordService.createRecord(onlineReq);
        // 更新投票人数
        voteInfoMapper.updateVoteCount(voteInfoDO.getId());

    }


    @Override
    public void deleteUserResult(Integer id) {
        // 校验存在
        this.validateUserResultExists(id);
        // 删除
        userResultMapper.deleteById(id);
    }

    private void validateUserResultExists(Integer id) {
        if (userResultMapper.selectById(id) == null) {
            throw exception(USER_RESULT_NOT_EXISTS);
        }
    }

    @Override
    public VoteUserResultDO getUserResult(Integer id) {
        return userResultMapper.selectById(id);
    }

    @Override
    public List<VoteUserResultDO> getUserResultList(Collection<Integer> ids) {
        return userResultMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<VoteUserResultDO> getUserResultPage(VoteUserResultPageReqVO pageReqVO) {
        return userResultMapper.selectPage(pageReqVO);
    }

    @Override
    public List<VoteUserResultDO> getUserResultList(VoteUserResultExportReqVO exportReqVO) {
        return userResultMapper.selectList(exportReqVO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public VoteUserResultImportRespVO importVoteResultUsers(List<VoteUserResultImportExcelVO>importUsers,Integer voteId, boolean isUpdateSupport){
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        VoteInfoDO vote = existVote(voteId);

        VoteUserResultImportRespVO respVO = VoteUserResultImportRespVO.builder()
                .createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>())
                .failureUsernames(new LinkedHashMap<>()).build();

        importUsers.forEach(importUser -> {
            if (StrUtil.isBlank(importUser.getMobile())
                    || StrUtil.isBlank(importUser.getUserName())
//                    || StrUtil.isBlank(importUser.getGroupName())
                    || StrUtil.isBlank(importUser.getUnitName())
            ) {
                respVO.getFailureUsernames().put("姓名，编号,学科研究平台,课题组","必填字段不能为空");
                return ;
            }
            VoteDeptDO deptDO =  voteDeptMapper.getDeptByName(importUser.getUnitName());
            if(deptDO==null){
                respVO.getFailureUsernames().put("学科研究平台","名称不存在");
                return ;
            }

//            VoteDeptDO groupDO =  voteDeptMapper.getDeptByName(importUser.getGroupName());
//            if(groupDO==null){
//                respVO.getFailureUsernames().put("课题组","名称不存在");
//                return ;
//            }

            // 手机号是否存在
            VoteUserResultDO existUser = userResultMapper.selectByMobile(voteId,importUser.getMobile());

            // 投票参数设置
            VoteUserResultDO resultDO =  VoteUserResultConvert.INSTANCE.convert(importUser);
            resultDO.setVoteName(vote.getVoteName());
            resultDO.setVoteId(voteId);
            resultDO.setVoteType(vote.getVoteType());

            resultDO.setUnitName(StrUtil.cleanBlank(resultDO.getUnitName()));
            resultDO.setDeptId(deptDO.getId());
//            resultDO.setGroupName(StrUtil.cleanBlank(resultDO.getGroupName()));
//            resultDO.setGroupId(groupDO.getId());
            if ("是".equals(importUser.getHasTeamLeader())) {
                resultDO.setVoteReviewerType(VoteReviewerTypeEnum.TEAM_LEADER.getValue());
            }else{
                resultDO.setVoteReviewerType(VoteReviewerTypeEnum.TEAM_MEMBER.getValue());
            }

            // 判断如果不存在，在进行插入
            if (existUser == null) {
                userResultMapper.insert(resultDO);
                VoteUserResultDetailDO detailDO = new VoteUserResultDetailDO();
                detailDO.setResultId(resultDO.getId().longValue());
                resultDetailMapper.insert(detailDO);

                respVO.getCreateUsernames().add(importUser.getUserName());
                return;
            }
            // 如果存在，判断是否允许更新
            if (!isUpdateSupport) {
                respVO.getFailureUsernames().put(importUser.getMobile(), USER_INFO_EXISTS.getMsg());
                return;
            }
            resultDO.setId(existUser.getId());
            userResultMapper.updateById(resultDO);
            respVO.getUpdateUsernames().add(importUser.getUserName());
        });

        // 更新导入数量
        updateVoteImportCount(voteId);

        return respVO;
    }

    /**
     * 投票规则判断
     * @param voteId
     * @return
     */
    private VoteInfoDO existVote(Integer voteId){

        VoteInfoDO voteInfoDO = redisService.getCacheObject(StrUtil.format(RedisConst.VOTE_INFO,voteId));
        if(voteInfoDO==null){
            voteInfoDO = voteInfoMapper.selectById(voteId);
        }
        if(voteInfoDO ==null){
            throw exception(INFO_NOT_EXISTS);
        }
        return voteInfoDO;
    }

    /**
     * 更新导入的数量
     * @param voteId
     */
    private void updateVoteImportCount(Integer voteId){
        Long count = userResultMapper.countByVoteId(voteId);
        VoteInfoDO vote = new VoteInfoDO();
        vote.setId(voteId);
        vote.setImportCount(String.valueOf(count));
        voteInfoMapper.updateById(vote);
    }

    /**
     * 统计组数
     * @param voteId
     * @return
     */

    private VoteYearUserResultGroupRespVO groupByGroupName(Integer voteId, Integer deptId, Integer total){
        VoteConfigDO config = voteConfigMapper.select(voteId,deptId,null);
        VoteYearUserResultGroupRespVO cate = new VoteYearUserResultGroupRespVO();
        cate.setTotal(total);
        if(config==null){
            return cate;
        }


        if (VoteConfigTypeEnum.RATE.getValue().equals(config.getConfigType())) {
            Float maxCount = 0.0F;
            if(total<config.getSpecialVote()){
                maxCount = total * config.getSpecialMaxCount();
            }else{
                maxCount = total * config.getExcellentMaxCount();
            }
            cate.setExcellentMaxCount(Math.floor(maxCount));
        }else if(VoteConfigTypeEnum.PEOPLE.getValue().equals(config.getConfigType())){
            Float maxCount = total<config.getSpecialVote()?
                    config.getSpecialMaxCount():config.getExcellentMaxCount();

            cate.setExcellentMaxCount(maxCount.doubleValue());
        }
        return cate;
    }


    /**
     *
     * @param voteId
     * @param groupName
     * @return
     */
    @Override
    public List<VoteUserResultDO> getByVoteIdAndGroupId(Integer voteId, Integer groupId){

        FieldDynamicsConfigDO dynamicsConfigDO = dynamicsConfigService.getByTableName(VoteUserResultDO.class);
        Predicate predicate = dynamicsConfigService.getDynamicFields(dynamicsConfigDO);
        List<FieldInfoVO> orderList = JSONObject.parseArray(dynamicsConfigDO.getOrderList(),FieldInfoVO.class);

        return userResultMapper.getByVoteIdAndGroupName(voteId,groupId,predicate,orderList);
    }


    /**
     * @param paramsVO
     * @return
     */
    @Override
    public List<VoteYearUserResultDeptRespVO> getH5VoteList(OnlineVoteParamsVO paramsVO,Long deptId){

//        String key = StrUtil.format(VOTEUSERRESULTH5LIST_KEY,paramsVO.getVoteId());
//
//        List<VoteYearUserResultDeptRespVO> deptRespVOS = redisService.getCacheList(key);
//        if(CollUtil.isNotEmpty(deptRespVOS)){
//            if(deptId==null){
//                return deptRespVOS;
//            }
//            for(VoteYearUserResultDeptRespVO respVO:deptRespVOS){
//                if(respVO.getDeptId().equals(deptId)){
//                    return Arrays.asList(respVO);
//                }
//            }
//        }

        Integer voteReviewerType = null;
        if(VotePersonTypeEnum.TEAM_MEMBER.getValue().equals(paramsVO.getVotePersonType())){
            voteReviewerType = VoteReviewerTypeEnum.TEAM_LEADER.getValue();
        }else if(VotePersonTypeEnum.TEAM_LEADER.getValue().equals(paramsVO.getVotePersonType())){
            voteReviewerType = VoteReviewerTypeEnum.TEAM_MEMBER.getValue();
        }

        List<VoteUserResultDO> unitNameList = userResultMapper.getByUnitName(paramsVO.getVoteId(),deptId,voteReviewerType);
        List<VoteYearUserResultDeptRespVO> deptRespVOS =  buildNestedStructure(unitNameList);
//        redisService.setCacheList(key,deptRespVOS);

        return deptRespVOS;
    }



    public List<VoteYearUserResultDeptRespVO> getH5UserVotedList(OnlineVoteParamsVO paramsVO,String ip){

        List<VoteUserResultDO> resultDOList = userResultMapper.getByVoteIdAndIp(paramsVO.getVoteId(),ip);

        List<VoteYearUserResultDeptRespVO> deptRespVOS =  buildNestedStructure(resultDOList);
        return deptRespVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void countVoteResult(Integer voteId){

//        VoteInfoDO vote = voteInfoMapper.selectById(voteId);

        List<VoteUserResultDO> updateList = new ArrayList<>();
        List<VoteRecordCountVO> recordCountList = recordDetailMapper.countVoteRecord(voteId);
        for(VoteRecordCountVO recordCountVO:recordCountList){
            VoteUserResultDO resultDO = getUserResult(recordCountVO.getUserResultId());
            resultDO.setTotal(recordCountVO.getTotal());
            // 统计平均分
            scopeStrategyFactory.getStrategy("partyLeadersScopeStrategy").avgScope(resultDO,voteId);
            // 打分形式
//            if (VoteModeEnum.SCOPE.getValue().equals(vote.getVoteMode())) {
//                BigDecimal avg =  NumberUtil.div(recordCountVO.getQuantifiedScore(),recordCountVO.getTotal(),2);
//                if(recordCountVO.getTotal()<3){
//                    resultDO.setQuantifiedScore(avg.floatValue());
//                    resultDO.setAvgScore(avg.floatValue());
//                }else {
//                    Integer minMaxCount = recordCountVO.getTotal()-2;
//                    Float minMaxTotal = recordCountVO.getQuantifiedScore()-recordCountVO.getMinScore()-recordCountVO.getMaxScore();
//                    BigDecimal minMaxAvg = NumberUtil.div(minMaxTotal,minMaxCount,2);
//                    resultDO.setQuantifiedScore(avg.floatValue());
//                    resultDO.setAvgScore(minMaxAvg.floatValue());
//                }
//            }
            updateList.add(resultDO);
        }
        updateBatchById(updateList);
    }



//    @Resource
//    private ScopeCalcService scopeCalcService;
//
//
//    private Float testScope(Integer userResultId,Integer voteId){
//        List<VoteRecordCountVO> scopeList = recordDetailMapper.getByResultId(voteId,userResultId,false,false);
//        List<VoteRecordCountVO> managerList = recordDetailMapper.getByResultId(voteId,userResultId,true,false);
//        List<VoteRecordCountVO> deptList = recordDetailMapper.getByResultId(voteId,userResultId,false,true);
//
//        scopeCalcService.getScopeCalcStrategy("TestScope");
//        BigDecimal result =scopeCalcService.scopeCalc(scopeList,false);
//        result.add(scopeCalcService.scopeCalc(managerList, true));
//        result.add(scopeCalcService.scopeCalc(deptList, false));
//
//        result=result.multiply(new BigDecimal(100));
//        return result.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
//    }

//    private Float testScope(Integer userResultId,Integer voteId){
//        List<VoteRecordCountVO> otherLeadersList = recordDetailMapper.getByResultId(voteId,userResultId, VotePersonTypeEnum.OTHER_LEADERS.getValue());
//        List<VoteRecordCountVO> partyLeaderList = recordDetailMapper.getByResultId(voteId,userResultId,VotePersonTypeEnum.PARTY_LEADER.getValue());
//        List<VoteRecordCountVO> teamLeaderList = recordDetailMapper.getByResultId(voteId,userResultId,VotePersonTypeEnum.TEAM_LEADER.getValue());
//        List<VoteRecordCountVO> teamMemberList = recordDetailMapper.getByResultId(voteId,userResultId,VotePersonTypeEnum.TEAM_MEMBER.getValue());
//
//        Double scope=0D;
//        scope+=calcScope(scopeList,false);
//        scope+=calcScope(managerList,true);
//        scope+=calcScope(deptList,false);
//
//        scope = scope*100;
//
//        if(scope==null || scope==0){
//            return 0f;
//        }
//        BigDecimal bg = new BigDecimal(scope);
//        return bg.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
//    }
//
//    private Double calcScope(List<VoteRecordCountVO> scopeList,Boolean isManager){
//        if(CollUtil.isEmpty(scopeList)){
//            return 0D;
//        }
//        Double scope = 1D;
//        for(VoteRecordCountVO countVO:scopeList){
//            scope = countVO.getExcellentCount()+countVO.getQualifiedCount()*0.8+countVO.getBaseQualifiedCount()*0.6+countVO.getUnqualifiedCount()*0.4;
//            scope= scope*(isManager?0.4:0.3)/countVO.getTotal();
//        }
//        return scope;
//    }


    /**
     * 测试分计算
     * @param voteId
     * @return
     */
//    private Float testScope(Integer userResultId,Integer voteId){
//        List<VoteRecordCountVO> scopeList = recordDetailMapper.getByResultId(voteId,userResultId,false,false);
//        List<VoteRecordCountVO> managerList = recordDetailMapper.getByResultId(voteId,userResultId,true,false);
//        List<VoteRecordCountVO> deptList = recordDetailMapper.getByResultId(voteId,userResultId,false,true);
//
//        Double scope=0D;
//        scope+=calcScope(scopeList,false);
//        scope+=calcScope(managerList,true);
//        scope+=calcScope(deptList,false);
//
//        scope = scope*100;
//
//        if(scope==null || scope==0){
//            return 0f;
//        }
//        BigDecimal bg = new BigDecimal(scope);
//        return bg.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
//    }
//
//    private Double calcScope(List<VoteRecordCountVO> scopeList,Boolean isManager){
//        if(CollUtil.isEmpty(scopeList)){
//            return 0D;
//        }
//        Double scope = 1D;
//        for(VoteRecordCountVO countVO:scopeList){
//            scope = countVO.getExcellentCount()+countVO.getQualifiedCount()*0.8+countVO.getBaseQualifiedCount()*0.6+countVO.getUnqualifiedCount()*0.4;
//            scope= scope*(isManager?0.4:0.3)/countVO.getTotal();
//        }
//        return scope;
//    }

//
//
    @Override
    public List<VoteUserResultGroupVO> countByGroupNameSort(Integer voteId,String applyType){
        List<VoteUserResultGroupVO>  resultGroupList =  userResultMapper.countByGroupNameSort(voteId,applyType);

        Integer sort = 0;
        String gn = "";
        Map<String,Integer> groupTotal = new HashMap<>();
        for(int i=0;i<resultGroupList.size();i++){
            if(resultGroupList.get(i).getApplyType()==null){
                continue;
            }
            if(!gn.equals(resultGroupList.get(i).getApplyType())){
                gn = resultGroupList.get(i).getApplyType();
                sort=1;
            }
            resultGroupList.get(i).setGroupSort(sort++);
            groupTotal.put(gn,resultGroupList.get(i).getGroupSort());
        }

        for(VoteUserResultGroupVO groupVO:resultGroupList){
            Integer total = groupTotal.get(groupVO.getApplyType());
            if(total!=null){
                groupVO.setGroupTotal(total);
            }
        }
        return resultGroupList;
    }

}
